/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package boundaries;

import business.EventManager;
import business.SearchingManager;
import entity.Event;
import entity.Participant;
import entity.User;
import entity.Visibility;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.List;
import java.util.TimeZone;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ApplicationScoped;
import javax.inject.Named;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;

/**
 *
 * @author Alessandro This bean handles the principal operations done on the
 * events.
 */
@ManagedBean
@SessionScoped
public class EventBean implements Serializable {

    private Event event;

    private Event eventViewed;

    private long eventViewedId;

    private int oldInvited;

    private User selectedInvited;

    private List<String> invited = new ArrayList();

    private List<String> invitedView = new ArrayList();

    private List<Participant> participantList = new ArrayList();

    @EJB
    private EventManager em;

    /**
     * Creates a new instance of EventBean
     */
    public EventBean() {
    }

    /**
     * If event is null then it'll create a new one
     *
     * @return
     */
    public Event getEvent() {
        if (event == null) {
            // kinda "defensive" programming. in order not to have any issue with the invited list, it is cleared.
            invitedView.clear();
            event = new Event();
        }
        return event;
    }

    public void setEvent(Event event) {
        this.event = event;
    }

    public EventManager getEm() {
        return em;
    }

    public void setEm(EventManager em) {
        this.em = em;
    }

    public User getSelectedInvited() {
        return selectedInvited;
    }

    public void setSelectedInvited(User selectedInvited) {
        this.selectedInvited = selectedInvited;
    }

    public List<String> getInvited() {
        return invited;
    }

    public void setInvited(List<String> invited) {
        this.invited = invited;
    }

    public Event getEventViewed() {
        return eventViewed;
    }

    public void setEventViewed(Event eventViewed) {
        this.eventViewed = eventViewed;
    }

    public long getEventViewedId() {
        return eventViewedId;
    }

    public void setEventViewedId(long eventViewedId) {
        this.eventViewedId = eventViewedId;
    }

    public int getOldInvited() {
        return oldInvited;
    }

    public void setOldInvited(int oldInvited) {
        this.oldInvited = oldInvited;
    }

    public List<String> getInvitedView() {
        return invitedView;
    }

    public void setInvitedView(List<String> invitedView) {
        this.invitedView = invitedView;
    }

    public List<Participant> getParticipantList() {
        return participantList;
    }

    public void setParticipantList(List<Participant> participantList) {
        this.participantList = participantList;
    }

    /**
     * this method recalls the event manager to create the event
     *
     * @return the home page
     */
    public String save() {
        System.out.println(this.getInvited().toString());
        em.create(event, invited);
        System.out.println(event.getTitle());
        event = null;
        invited.clear();
        return "home";
    }

    /**
     * this method only adds the user's email to the invited list
     */
    public void invite() {
        System.out.println("chiamto invited" + selectedInvited.getEmail());
        if (canInvite(selectedInvited, invited) && canInvite(selectedInvited, invitedView)) {
            this.invited.add(selectedInvited.getEmail());
            System.out.println(invited.toString());
        } else {
            FacesContext context = FacesContext.getCurrentInstance();
            context.addMessage(null, new FacesMessage("Unable to invite this User"));
        }
    }

    /**
     * this method calls the event manager to modify a specific event
     *
     * @return the event page
     */
    public String modify() {
        System.out.println("sto modificando l'evento");
        System.out.println("Lista di vecchi invitati: " + invitedView.toString());
        System.out.println("Lista di nuovi invitati: " + invited.toString());

        invitedView.addAll(invited);
        System.out.println("Lista di completi invitati: " + invitedView.toString());
        System.out.println("Lista di vecchi invitati #: " + oldInvited);

        em.modify(eventViewed, invitedView, oldInvited);
        invited.clear();
        invitedView.clear();
        return "eventPage?faces-redirect=true&idEv=" + eventViewedId;
    }

    public String delete() {
        System.out.println("sto cancellando l'evento");
        em.deleteEvent(eventViewed);
        return "myEvents";
    }

    public String join() {
        em.joinInvitation(eventViewed);
        return "eventPage?faces-redirect=true&idEv=" + eventViewedId;
    }

    public String decline() {
        em.declineInvitation(eventViewed);
        return "eventPage?faces-redirect=true&idEv=" + eventViewedId;
    }

    /**
     * this method loads a specific event
     */
    public void loadEvent() {
        invited.clear();
        invitedView.clear();
        participantList.clear();
        eventViewed = em.findEvent(eventViewedId);
        participantList.addAll(eventViewed.getParticipantCollection());
        for (Participant p : eventViewed.getParticipantCollection()) {
            invitedView.add(p.getUser1().getEmail());
        }
        oldInvited = invitedView.size();
        System.out.println(eventViewed.getId());
    }

    /**
     * check if the user is the creator
     *
     * @return true is the user is the creator
     */
    public boolean checkCreator() {
        return (em.checkCreator(eventViewed));
    }

    /**
     * checks if the user is a participant
     *
     * @return true if the user is a participant but no the creator
     */
    public boolean checkParticipant() {
        return (em.checkParticipant(eventViewed));
    }

    public String invitings(String backPage) {
        return "invitings?faces-redirect=true&page=" + backPage;
    }

    /**
     * this method reset all the fields of a new if you click on "home" link
     *
     * @return
     */
    public String backHome() {
        //this can be done, because the case is handled in getEvent() method
        event = null;
        invited.clear();
        return "home?faces-redirect=true";
    }

    public String back() {
        return "newEventPage";
    }

    private boolean canInvite(User invited, List<String> invitedList) {
        if (!invited.equals(em.getLoggedUser())) {
            for (String inv : invitedList) {
                //i'm already invited
                if (invited.getEmail().equals(inv) || invited.equals(em.getLoggedUser())) {
                    System.out.println("torno false");
                    return false;
                }
            }
            System.out.println("sto per tornare true");
            return true;
        } else {
            //i'm the creator;
            return false;
        }
    }

    /**
     * The function that decides to render or not the form that inables the user
     * to execute operations on the event page
     *
     * @return true if the event starts after the current time
     */
    public boolean checkFormRender() {
        if (eventViewed.getStartDate().after(Calendar.getInstance().getTime())) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Controls if the user is joining the event viewed in that moment
     *
     * @return true if the user is joining the event
     */
    public boolean checkJoining() {
        User logged = em.getLoggedUser();
        Collection<Participant> participants = eventViewed.getParticipantCollection();
        for (Participant p : participants) {
            if (p.getUser1().equals(logged)) {
                if (p.getAnswer().equals("yes")) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Controls if the user is declining the event viewed in that moment
     *
     * @return true if the user is declining the event
     */
    public boolean checkDeclining() {
        User logged = em.getLoggedUser();
        Collection<Participant> participants = eventViewed.getParticipantCollection();
        for (Participant p : participants) {
            if (p.getUser1().equals(logged)) {
                if (p.getAnswer().equals("no")) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * the function checking if the event selected is accessible to the logged
     * user. this function allow to prevent of showing details of a private
     * event
     *
     * @return true if the logged user is private
     */
    public boolean checkPrivate() {
        if (eventViewed.getVisibiltiy().equals(Visibility.PRIVATE)) {
            for (Participant p : eventViewed.getParticipantCollection()) {
                if (p.getUser1().equals(em.getLoggedUser())) {
                    return false;
                }
            }
            //Se alla fine del for non s è trovato l'utente:
            return true;
        }
        //Se l'evento non è PRIVATE
        return false;
    }

    /**
     * this method allows to delete an user from the invited list meanwhile
     * vreating or modifying the event
     *
     * @param user the one to be removed
     */
    public void remove(String user) {
        invited.remove(user);
    }

    public String getTimeZone() {
        return Calendar.getInstance().getTimeZone().getID();
    }

    public String getImage() {
        int code = eventViewed.getForecast().getWeatherCode();
        if (code >= 200 && code <= 232) {
            return "../resources/images/storm.png";
        }
        if (code >= 300 && code <= 531) {
            return "../resources/images/rain.png";
        }
        if (code >= 600 && code <= 612) {
            return "../resources/images/snow.png";
        }
        if (code >= 615 && code <= 622) {
            return "../resources/images/snow_rain.png";
        }
        if (code >= 800 && code <= 801) {
            return "../resources/images/sunny.png";
        }
        if (code >= 802 && code <= 804) {
            return "../resources/images/partly_cloudy.png";
        }
        if (code >= 701 && code < 781) {
            return "../resources/images/fog.png";
        }
        if ((code >= 900 && code < 2000 ) || code == 781) {
            return "../resources/images/windy.png";
        }
        return "../resources/images/unavailable_weather.png";
    }
}
